package com.entrogy.service.impl;

import com.entrogy.bean.PayFormEntity;
import com.entrogy.bean.PayOrderEntity;
import com.entrogy.bean.PayProduct;
import com.entrogy.bean.WeixinEntity;
import com.entrogy.dao.PayMapper;
import com.entrogy.dao.WeixinMapper;
import com.entrogy.service.PayService;
import com.entrogy.utils.UUIDUtils;
import com.entrogy.utils.pay.HttpRequest;
import com.entrogy.utils.pay.WXPayUtil;
import com.entrogy.utils.pay.WechatConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;

@Service
@Transactional
public class PayServiceImpl implements PayService {

    private static final Logger logger = LoggerFactory.getLogger(PayServiceImpl.class);

    @Autowired
    private PayMapper payMapper;
    @Autowired
    private WeixinMapper weixinMapper;

    @Override
    public PayProduct getPayProductByID(int productId) {
        return payMapper.getPayProductByID(productId);
    }

    @Override
    public Map<String, Object> wxPay(PayFormEntity payForm) {
        Map<String,Object> returnMap = new HashMap<>();
        try {
            //生成的随机字符串
            String nonce_str = WXPayUtil.generateNonceStr();
            //获取客户端的ip地址
            //组装参数，用户生成统一下单接口的签名
            Map<String, String> packageParams = new HashMap<>();
            packageParams.put("appid", WechatConfig.appid);
            packageParams.put("mch_id", WechatConfig.mch_id);
            packageParams.put("nonce_str", nonce_str);
            packageParams.put("body", payForm.getBody());//商品描述
            //生成订单号
            String orderId = UUIDUtils.getUUID();
            packageParams.put("out_trade_no",orderId);//商户订单号,自己的订单ID
            //根据商品ID去查询订单金额
            BigDecimal totalFee = payMapper.getProductPriceById(payForm.getProductId());
            BigDecimal bigDecimal = new BigDecimal(100);//微信支付已分为单位支付宝已元为单元（总额度不能有小数点）
            String sellMoney = totalFee.multiply(bigDecimal).toString();
            packageParams.put("total_fee",sellMoney.substring(0,sellMoney.indexOf(".")));//支付金额，这边需要转成字符串类型，否则后面的签名会失败
            packageParams.put("spbill_create_ip", "127.0.0.1");//发起微信支付API的IP//TODO ---上线需要改的地方
            packageParams.put("notify_url", WechatConfig.notify_url);//支付成功后的回调地址
            packageParams.put("trade_type", WechatConfig.TRADETYPE);//支付方式
            WeixinEntity weixinEntity = weixinMapper.getWeixinByUid(payForm.getUid());//根据用户ID去查询其对应的openid
            packageParams.put("openid", weixinEntity.getOpenid());
            String sign = WXPayUtil.generateSignature(packageParams, WechatConfig.key);
            packageParams.put("sign", sign);
            String xml = WXPayUtil.mapToXml(packageParams);
            //操作DB 插入信息到支付订单表(我们的订单商品默认是没有失效的is_out_of_date=1)
            payMapper.insertPayOrder(payForm.getProductId(),payForm.getUid(),totalFee,orderId,payForm.getStudentId());
            logger.info(xml);
            String xmlStr = HttpRequest.sendPost(WechatConfig.pay_url, xml);
            Map<?, ?> map = WXPayUtil.xmlToMap(xmlStr);
            logger.info("用户"+payForm.getUid()+"=====>openid为"+weixinEntity.getOpenid()+"微信支付统一下单后返回给我们的结果"+new String(xmlStr.getBytes(),"utf-8"));
            String return_code = (String) map.get("return_code");//返回状态码
            String result_code = (String) map.get("result_code");//返回状态码
            String paySign = new String();
            Map<String, String> response = new HashMap<String, String>();//返回给小程序端需要的参数
            if (return_code.equals("SUCCESS" )&& return_code.equals(result_code)) {
                String prepay_id = (String) map.get("prepay_id");//返回的预付单信息
                response.put("nonceStr", nonce_str);//生成的随机字符串
                response.put("package", "prepay_id=" + prepay_id);
                Long timeStamp = System.currentTimeMillis() / 1000;
                response.put("timeStamp", timeStamp + "");//这边要将返回的时间戳转化成字符串，不然小程序端调用wx.requestPayment方法会报签名错误
                //拼接签名需要的参数
                paySign = WXPayUtil.MD5("appId="+WechatConfig.appid+"&nonceStr="+nonce_str+"&package=prepay_id="+prepay_id+"&signType=MD5&timeStamp="+timeStamp+""+"&key="+WechatConfig.key+"");
                response.put("paySign", paySign);
                response.put("appid", WechatConfig.appid);
                returnMap.put("data",response);
                returnMap.put("code",1);
                returnMap.put("msg","预支付成功");
                logger.info("用户"+payForm.getUid()+"=====>openid为"+payForm.getOpenId()+"微信支付统一下单返回给用户成功");
            }else {
                response.put("err_code_des", (String) map.get("err_code_des"));
                returnMap.put("data",response);
                returnMap.put("code",0);
                returnMap.put("msg","预支付失败");
            }
        }catch (Exception e) {
            returnMap.put("code",0);
            returnMap.put("msg","预支付失败");
            returnMap.put("data","");
        }
        return returnMap;
    }
    //这里是支付回调接口，微信支付成功后会自动调用
    @Override
    public String wxNotify(HttpServletRequest request) {
        Map<String,String> returnMap = new HashMap<>();
        BufferedReader br;
        String orderId = new String();
        try {
            /*读取微信支付完成后返回的结果*/
            br = new BufferedReader(new InputStreamReader(request.getInputStream()));
            String line = null;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            br.close();
            //sb为微信返回的xml
            String notityXml = sb.toString();
            logger.info("用户支付成功后微信回调==>返回给我们的信息========>>>>"+notityXml);
            Map map =  WXPayUtil.xmlToMap(notityXml);
            String returnCode = (String) map.get("return_code");
            if ("SUCCESS".equals(returnCode)) {
                if (WXPayUtil.isSignatureValid(notityXml, WechatConfig.key) ) {
                    String resultCode = (String) map.get("result_code");
                    String totalFee = (String) map.get("total_fee");//支付成功后回调返回的订单金额
                    int payTotalFee = Integer.parseInt(totalFee);
                    orderId = (String) map.get("out_trade_no");//订单号
                    BigDecimal totalPriceDB = payMapper.getProductPriceByOrderId(orderId);
                    if(("SUCCESS").equals(resultCode) && payTotalFee/100 == totalPriceDB.intValue()){//支付成功
                        payMapper.updatePayOrderIsSuccess(orderId);
                        returnMap.put("return_code","SUCCESS");
                        returnMap.put("return_msg","OK");
                    }else{
                        returnMap.put("return_code","FAIL");
                        returnMap.put("return_msg","参数校验错误");
                    }

                }else {
                    returnMap.put("return_code","FAIL");
                    returnMap.put("return_msg","参数校验错误");
                }
            } else {
                returnMap.put("return_code","FAIL");
                returnMap.put("return_msg","签名失败");
            }
        } catch (IOException e) {
            e.printStackTrace();
            returnMap.put("return_code","FAIL");
            returnMap.put("return_msg","参数校验错误");
        } catch (Exception e) {
            e.printStackTrace();
            returnMap.put("return_code","FAIL");
            returnMap.put("return_msg","参数校验错误");
        }
        String resultMsg = null;
        try {
            resultMsg = WXPayUtil.mapToXml(returnMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.info("订单号为"+orderId+"支付回调返回给商户平台的结果为======>"+resultMsg);
        return resultMsg;
    }

    @Override
    public List<PayOrderEntity> getOrdersByUid(String uid,int beginIndex,int pageSize) {
        List<PayOrderEntity> lists = payMapper.getOrdersByUid(uid,beginIndex,pageSize);
        Calendar calendar = new GregorianCalendar();
        for (PayOrderEntity payOrderEntity : lists){
            payOrderEntity.setOrderTitle(payOrderEntity.getStudentName()+payOrderEntity.getProductName());
//            calendar.setTime(payOrderEntity.getCreateTime());
//            calendar.add(Calendar.YEAR, 1);//把日期往后增加一年.整数往后推,负数往前移动
//            payOrderEntity.setExpiryDate(calendar.getTime());
        }
        return lists;
    }

    @Override
    public int getPayOrderTotalCount(String uid) {
        Integer count = payMapper.getPayOrderTotalCount(uid);
        return count == null?0:count;
    }
}
